﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace LPBToolsLib
{
    public class HttpReqTools
    {

        private static readonly string DefaultUserAgent_FireFox = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0";
        private static readonly string DefaultUserAgent_Chrome = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36";
        private static readonly string DefaultUserAgent_QQ = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.196.400 QQBrowser/11.7.5286.400";
        /// <summary>
        /// Http的Post请求
        /// </summary>
        /// <param name="Url">目标地址</param>
        /// <param name="Paras">参数列表</param>
        /// <param name="appDHeader">追加的请求头，每行内必须包含冒号 (:) 字符</param>
        /// <returns></returns>
        public static string PostJSON(string Url, Dictionary<string, object> Paras,
            Dictionary<string, object> appDHeader, int timeOut = 5000)
        {
            if (Paras != null)
            {
                List<string> tHeaders = new List<string>();
                if ((appDHeader != null) && (appDHeader.Count > 0))
                    foreach (KeyValuePair<string, object> item in appDHeader)
                        tHeaders.Add(item.Key + ":" + item.Value);
                return PostJSON(Url, JsonConvert.SerializeObject(Paras),
                    tHeaders.ToArray(), timeOut);
            }
            return "";
        }

        /// <summary>
        /// Http的Post请求
        /// </summary>
        /// <param name="Url">目标地址</param>
        /// <param name="jsonParas">参数列表，必须是JSON格式的字符串</param>
        /// <param name="appHeaders">追加的请求头，每行内必须包含冒号 (:) 字符</param>
        /// <returns></returns>
        public static string PostJSON(string Url, string jsonParas, string[] appHeaders,
             int timeOut = 5000)
        {
            string strURL = Url;
            string postContent = "";
            //创建一个HTTP请求  
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(strURL);
            //Post请求方式  
            request.Method = "POST";
            //内容类型
            request.ContentType = "application/json;charset:utf-8";
            request.KeepAlive = true;
            request.UserAgent = DefaultUserAgent_FireFox;
            request.Timeout = timeOut;
            // 可能的异常:
            //   T:System.ArgumentException:
            //     header 不包含冒号 (:) 字符。 value 的长度大于 65535。 或 - header 的名称部分为 System.String.Empty，或者包含无效字符。
            //     或 - header 是应由属性设置的受限制的标头。 或 header 的值部分包含无效字符。
            if ((appHeaders != null) && (appHeaders.Length > 0))
                foreach (string item in appHeaders)
                    request.Headers.Add(item);

            //设置参数
            //进行URL编码 System.Web.HttpUtility.UrlEncode(jsonParas);
            string paraUrlCoded = jsonParas;

            byte[] payload;
            //将Json字符串转化为字节  
            payload = Encoding.UTF8.GetBytes(paraUrlCoded);
            //设置请求的ContentLength   
            request.ContentLength = payload.Length;
            //发送请求，获得请求流 

            Stream writer = null;
            try
            {
                //获取用于写入请求数据的Stream对象
                writer = request.GetRequestStream();
                //将请求参数写入流
                writer.Write(payload, 0, payload.Length);
            }
            finally
            {
                if (writer != null)
                {
                    writer.Close();//关闭请求流
                    writer = null;
                }
            }
            // String strValue = "";//strValue为http响应所返回的字符流
            HttpWebResponse response;
            Stream sTmp = null;
            try
            {
                //获得响应流
                response = (HttpWebResponse)request.GetResponse();
                sTmp = response.GetResponseStream();
            }
            catch (WebException ex)
            {
                response = ex.Response as HttpWebResponse;
                throw;
            }
            if (sTmp != null)
            {
                StreamReader sRead = null;
                try
                {
                    sRead = new StreamReader(sTmp);
                    postContent = sRead.ReadToEnd();
                }
                finally
                {
                    if (sRead != null)
                    {
                        sRead.Close();
                        sRead = null;
                    }
                }
            }
            return postContent;//返回Json数据
        }

        /// <summary>
        /// 进行Get请求
        /// 1、请求结果格式是JSON的，在请求的头中必须声明响应内容类型为JSON，声明客户端偏好语言为zh-cn，压缩算法使用gzip;
        /// 2、能够接受输入参数的头设置，合并与第1条中不冲突的信息；
        /// 3、在返回结果前，必须检测字符串是否符合JSON格式，不符合将返回空；
        /// 4、函数仅使用Newtonsoft.json作为json转换工具；
        /// 5、参数sError在请求失败的时候，返回错误代码及初步描述；
        /// 2025-04-29
        /// 有腾讯元宝基于混元大模型编写
        /// </summary>
        /// <param name="url">目标地址</param>
        /// <param name="appDHeader">特殊请求的头</param>
        /// <param name="sError">返回请求失败原因</param>
        /// <param name="timeOut">请求超时，单位：ms</param>
        /// <returns></returns>
        public static int GetRequest(string url, Dictionary<string, object> appDHeader, out string sResult, int timeOut = 5000)
        {
            sResult = string.Empty;
            int iResult = -1;
            if (string.IsNullOrEmpty(url))
            {
                sResult = "输入地址无效";
                return iResult;
            }
            try
            {
                using (HttpClient client = new HttpClient())
                {
                    // 设置超时时间
                    client.Timeout = TimeSpan.FromMilliseconds(timeOut);
                    // 创建默认请求头（必须包含的内容）
                    var headers = new Dictionary<string, string>
                {
                    { "Accept", "application/json" }, // 声明响应内容类型为JSON
                    { "Accept-Language", "zh-cn" }, // 声明客户端偏好语言为zh-cn
                    { "Accept-Encoding", "gzip" }    // 声明压缩算法为gzip
                };
                    // 合并用户自定义头（不覆盖默认头）
                    if ((appDHeader != null) && (appDHeader.Count > 0))
                    {
                        foreach (var header in appDHeader)
                            // 只添加默认头中不存在的字段
                            if (!headers.ContainsKey(header.Key))
                                headers[header.Key] = header.Value?.ToString();
                    }
                    // 设置请求头
                    foreach (var header in headers)
                        client.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value);

                    // 发送GET请求
                    HttpResponseMessage response = client.GetAsync(url).Result;
                    iResult= (int)response.StatusCode;
                    // 读取响应内容
                    sResult = response.Content.ReadAsStringAsync().Result;                    
                    // 检查JSON格式有效性
                    //if (!IsValidJson(sResult))
                    {
                     //   return -2;
                    }
                }
            }
            catch (HttpRequestException ex)
            {
                sResult = $"HTTP请求异常: {ex.Message}";
                return -3;
            }
            catch (Exception ex)
            {
                if (ex.Message.IndexOf("A task was canceled.")>0)
                    sResult = "请求超时";
                else
                if (ex.Message.IndexOf("or more errors occurred. (The ") > 0)
                    sResult = "无效的 URI";
                else
                    sResult = $"发生错误: {ex.Message}";
                return -4;
            }

            return iResult;
        }

        /// <summary>
        /// 检查字符串是否为有效的JSON格式
        /// </summary>
        public static bool IsValidJson(string strInput)
        {
            try
            {
                // 使用JToken.Parse尝试解析，如果抛出异常则不是有效JSON
                JToken.Parse(strInput);
                return true;
            }
            catch (JsonReaderException)
            {
                return false;
            }
        }
    }
}
